﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Xml;
using CapstoneProjectAEReader.Business.E_book_Reader;
using CapstoneProjectAEReader.Entities.Models;
using iTextSharp.text.pdf;
using Clipboard = System.Windows.Forms.Clipboard;
using TreeView = System.Windows.Controls.TreeView;
using GhostscriptSharp;
using GhostscriptSharp.Settings;
using System.Drawing;
using TextDataFormat = System.Windows.Forms.TextDataFormat;
using System.ComponentModel;


namespace CapstoneProjectAEReader.Business.E_book_Reader
{
    public partial class pdfReaderControl : IBook
    {
        public pdfReaderControl()
        {
            InitializeComponent();
        }

        public pdfReaderControl(int mode)
        {
            InitializeComponent();
        }

        public int counter = 0;
        public XmlDocument xDoc;
        public XmlNode node;
        public string xmlFilePath;
        public int intCurrentPageNumber = 0;
        private string filePath;
        private string progress = "Loading";

        public override void LoadFile(string strFileName)
        {
            //InitializeComponent();
            filePath = strFileName;
            startPDFLoading();


            //string strTotalPageNumber;
            //string xmlFileName;
            //string strTempFolder;


            //PdfReader pdf_file = new PdfReader(strFileName);
            ////read it's pagecount
            //int intPageCount = pdf_file.NumberOfPages;
            //axAcroPDF1.Visible = false;
            //axAcroPDF1.setShowToolbar(true);
            //axAcroPDF1.setLayoutMode("SinglePage");
            //axAcroPDF1.setView("FitH");
            //axAcroPDF1.setPageMode("none");
            //axAcroPDF1.setZoom(100);
            //axAcroPDF1.Visible = true;
            //axAcroPDF1.src = strFileName + "#toolbar=0&navpanes=0&scrollbar=0";
            //axAcroPDF1.BackColor = System.Drawing.Color.Black;
            //axAcroPDF1.ForeColor = System.Drawing.Color.Blue;
            //axAcroPDF1.Show();
            //axAcroPDF1.setPageMode("none");
            //strTempFolder = "AeReaderData\\Temp";
            //xmlFileName = Path.GetFileNameWithoutExtension(strFileName) + ".xml";
            //if (!Directory.Exists(strTempFolder))
            //{
            //    Directory.CreateDirectory(strTempFolder);
            //}
            //xmlFilePath = strTempFolder + "\\" + xmlFileName;
            //if (!File.Exists(xmlFilePath))
            //{
            //    ExportBookmarksToXml(strFileName, xmlFilePath, "");
            //}
        }



        #region Loading
        private void startPDFLoading()
        {
            BackgroundWorker worker = new BackgroundWorker();
            //worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CompleteLoading);
            worker.DoWork += new DoWorkEventHandler(DoLoading);
            worker.RunWorkerAsync();
        }

        void CompleteLoading(object sender, RunWorkerCompletedEventArgs e)
        {
            BackgroundWorker finishWorker = sender as BackgroundWorker;
            finishWorker.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(CompleteLoading);
            finishWorker.DoWork -= new DoWorkEventHandler(DoLoading);
            progress = "Done";
            //if (axAcroPDF1.InvokeRequired)
            //{
            //    axAcroPDF1.Invoke((Action)delegate { axAcroPDF1.Focus(); });
            //    return;
            //}
            //else {
            //    axAcroPDF1.Focus();
            //}
            
            //MessageBox.Show("Done");
        }

        private void DoLoading(object sender, DoWorkEventArgs e)
        {
            if (axAcroPDF1.InvokeRequired)
            {
                axAcroPDF1.Invoke((Action)delegate { DoLoading(sender, e); });
                return;
            }
            BackgroundWorker finishWorker = sender as BackgroundWorker;
            finishWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CompleteLoading);

            string xmlFileName;
            string strTempFolder;
            try
            {
                //Create XML BookMark
                string getFileName = Path.GetFileNameWithoutExtension(filePath);
                strTempFolder = "AeReaderData\\Temp";
                xmlFileName = getFileName + ".xml";
                if (!Directory.Exists(strTempFolder))
                {
                    Directory.CreateDirectory(strTempFolder);
                }
                //Create Cover
                string imageFilePath = strTempFolder + "\\" + getFileName + ".png";
                if (!File.Exists(imageFilePath))
                {
                    Thread thread = new Thread(() =>
                    {
                        GetPdfThumbnail(filePath, imageFilePath);
                        System.Windows.Threading.Dispatcher.Run();
                    });
                    thread.SetApartmentState(ApartmentState.STA);
                    thread.IsBackground = true;
                    thread.Start();

                }
                xmlFilePath = strTempFolder + "\\" + xmlFileName;
                if (!File.Exists(xmlFilePath))
                {
                    ExportBookmarksToXml(filePath, xmlFilePath, "");
                }

                

                axAcroPDF1.Visible = false;
                axAcroPDF1.setShowToolbar(true);
                axAcroPDF1.setLayoutMode("SinglePage");
                axAcroPDF1.setView("FitH");
                axAcroPDF1.setPageMode("none");
                axAcroPDF1.setZoom(100);
                axAcroPDF1.Visible = true;
                axAcroPDF1.src = filePath + "#toolbar=0&navpanes=0&scrollbar=0";
                axAcroPDF1.BackColor = System.Drawing.Color.Black;
                axAcroPDF1.ForeColor = System.Drawing.Color.Blue;
                axAcroPDF1.Show();
                axAcroPDF1.setPageMode("none");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public override string CheckLoading()
        {
            return progress;
        }
        #endregion

        public static void ExportBookmarksToXml(string SourcePdfPath, string xmlOutputPath, string Password = "")
        {
            try
            {
                PdfReader reader = new PdfReader(SourcePdfPath, new System.Text.ASCIIEncoding().GetBytes(Password));
                IList<Dictionary<string, object>> bookmarks = SimpleBookmark.GetBookmark(reader);
                using (MemoryStream memoryStream = new MemoryStream())
                {
                    SimpleBookmark.ExportToXML(bookmarks, memoryStream, "ISO8859-1", true);
                    //MessageBox.Show(bookmarks[0].Values.ToString());
                    File.WriteAllBytes(xmlOutputPath, memoryStream.ToArray());
                }
            }
            catch (Exception)
            {
                PdfReader reader = new PdfReader(SourcePdfPath);
                XmlDocument XD = new XmlDocument();
                XmlNode Root = XD.AppendChild(XD.CreateElement("Bookmark"));
                XmlElement childElement = XD.CreateElement("Title");
                childElement.InnerText = "First Page";
                childElement.SetAttribute("Page", "1 ");
                childElement.SetAttribute("Action", "GoTo");
                Root.AppendChild(childElement);
                childElement = XD.CreateElement("Title");
                childElement.InnerText = "Last Page";
                childElement.SetAttribute("Page", reader.NumberOfPages.ToString() + " ");
                childElement.SetAttribute("Action", "GoTo");
                Root.AppendChild(childElement);
                XmlDeclaration xmldecl;
                xmldecl = XD.CreateXmlDeclaration("1.0", null, null);
                xmldecl.Encoding = "ISO-8859-1";
                xmldecl.Standalone = "yes";
                XD.Save(xmlOutputPath);
            }
        }

        private void axAcroPDF1_OnError(object sender, EventArgs e)
        {
        }

        /// <summary>
        /// Display next page
        /// </summary>
        public override void DisplayNextPage()
        {
            //MessageBox.Show(axAcroPDF1.Location.Y.ToString());
            axAcroPDF1.gotoNextPage();
            intCurrentPageNumber++;
        }

        /// <summary>
        /// Display previous page
        /// </summary>
        public override void DisplayPrevioudPage()
        {
            axAcroPDF1.gotoPreviousPage();
            if (intCurrentPageNumber > 0)
            {
                intCurrentPageNumber--;
            }
        }

        /// <summary>
        /// Display first page
        /// </summary>
        public override void DisplayFirstPage()
        {
            axAcroPDF1.gotoFirstPage();
            intCurrentPageNumber = 1;
        }

        /// <summary>
        /// Display last page
        /// </summary>
        public override void DisplayLastPage()
        {
            axAcroPDF1.gotoLastPage();
        }

        /// <summary>
        /// Zoom in
        /// </summary>
        public override void ZoomIn()
        {
            counter += 10;
            float zoom = 0;
            zoom = 60 + counter;

            //curSize = float.Parse(this.axAcroPDF1.);
            //curSize += float.Parse("0.5".ToString());
            axAcroPDF1.setZoom(zoom);
        }

        /// <summary>
        /// Zoom out
        /// </summary>
        public override void ZoomOut()
        {
            counter -= 10;
            float zoom = 0;
            zoom = 60 + counter;

            //curSize = float.Parse(this.axAcroPDF1.);
            //curSize += float.Parse("0.5".ToString());
            axAcroPDF1.setZoom(zoom);
        }

        /// <summary>
        /// Go to specific page
        /// </summary>
        /// <param name="pageNumber">Desired Page Number</param>
        public override void GoToPage(int intPageNumber)
        {
            axAcroPDF1.setCurrentPage(intPageNumber);
        }

        /// <summary>
        /// Open Note Form
        /// </summary>
        /// <param name="selectedContent">selected content</param>
        public override string GetSelectedText()
        {
            String strSelectedText = Clipboard.GetText(TextDataFormat.UnicodeText);
            Clipboard.Clear();
            return strSelectedText;
        }

        /// <summary>
        /// Add new bookmark
        /// </summary>
        /// <param name="tempBm">new bookmark</param>
        public override void AddBookmark(RoutedPropertyChangedEventArgs<object> e, string strSelectedItem, string strAddingItem, string strPageNumber)
        {
            string strBookmarkPageNumber = "";
            string strNodePath = "/Bookmark/";
            Stack<TreeViewItem> path = GetNodeParent(e.NewValue as UIElement);
            foreach (var treeViewItem in path)
            {
                strNodePath += "Title" + "/";
            }
            if (strNodePath.Length > 1)
            {
                //strNodePath += strSelectedItem.Substring(0, strSelectedItem.Length -1);
            }

            strNodePath = strNodePath.Substring(0, strNodePath.Length - 1);


            //strNodePath = "/Bookmark/Title/Title[contains(text(),'Errata')]";
            strNodePath += "[contains(text(),'" + strSelectedItem.Trim() + "')]";
            node = xDoc.SelectSingleNode(strNodePath);
            if (node != null)
            {
                XmlElement childElement = xDoc.CreateElement("Title");
                childElement.InnerText = strAddingItem;
                childElement.SetAttribute("Page", strPageNumber + " ");
                childElement.SetAttribute("Action", "GoTo");
                node.ParentNode.AppendChild(childElement);
            }
            xDoc.Save(xmlFilePath);
            xDoc.Load(xmlFilePath);
        }

        /// <summary>
        /// Delete bookmark
        /// </summary>
        /// <param name="tempBm"></param>
        public override void DeleteBookmark(RoutedPropertyChangedEventArgs<object> e, string strSelectedItem)
        {
            string strBookmarkPageNumber = "";
            string strNodePath = "/Bookmark/Title/";
            Stack<TreeViewItem> path = GetNodeParent(e.NewValue as UIElement);
            foreach (var treeViewItem in path)
            {
                strNodePath += "Title" + "/";
            }
            if (strNodePath.Length > 1)
            {
                //strNodePath += strSelectedItem.Substring(0, strSelectedItem.Length -1);
            }

            strNodePath = strNodePath.Substring(0, strNodePath.Length - 1);


            //strNodePath = "/Bookmark/Title/Title[contains(text(),'Errata')]";
            strNodePath += "[contains(text(),'" + strSelectedItem.Trim() + "')]";
            node = xDoc.SelectSingleNode(strNodePath);
            if (node != null)
            {
                node.ParentNode.RemoveChild(node);
            }
            xDoc.Save(xmlFilePath);
            xDoc.Load(xmlFilePath);
        }

        /// <summary>
        /// Update bookmark
        /// </summary>
        /// <param name="tempBm"></param>
        public override void UpdateBookmark(RoutedPropertyChangedEventArgs<object> e, string strSelectedItem, string strUpdateItem)
        {
            string strBookmarkPageNumber = "";
            string strNodePath = "/Bookmark/";
            Stack<TreeViewItem> path = GetNodeParent(e.NewValue as UIElement);
            foreach (var treeViewItem in path)
            {
                strNodePath += "Title" + "/";
            }
            if (strNodePath.Length > 1)
            {
                //strNodePath += strSelectedItem.Substring(0, strSelectedItem.Length -1);
            }

            strNodePath = strNodePath.Substring(0, strNodePath.Length - 1);


            //strNodePath = "/Bookmark/Title/Title[contains(text(),'Errata')]";
            strNodePath += "[contains(text(),'" + strSelectedItem.Trim() + "')]";
            node = xDoc.SelectSingleNode(strNodePath);
            if (node != null)
            {
                node.InnerText = strUpdateItem;
            }
            xDoc.Save(xmlFilePath);
            xDoc.Load(xmlFilePath);
        }



        /// <summary>
        /// Load Bookmark
        /// </summary>
        /// <returns></returns>
        public override void LoadBookmark(System.Windows.Controls.TreeView tvBookmark, string xmlPath)
        {
            try
            {
                //Just a good practice -- change the cursor to a 
                //wait cursor while the nodes populate
                //this.Cursor = Cursors.Wait;
                //First, we'll load the Xml document
                xmlFilePath = xmlPath;
                xDoc = new XmlDocument();
                xDoc.Load(xmlFilePath);

                //Now, clear out the treeview, 
                //and add the first (root) node

                tvBookmark.Items.Clear();
                TreeViewItem nodeToAdd = new TreeViewItem();
                nodeToAdd.Header = xDoc.DocumentElement.Name;
                tvBookmark.Items.Add(nodeToAdd);
                TreeViewItem tNode = new TreeViewItem();
                tNode = (TreeViewItem)tvBookmark.Items[0];
                //We make a call to addTreeNode, 
                //where we'll add all of our nodes
                addTreeNode(xDoc.DocumentElement, tNode);
                foreach (TreeViewItem item in tvBookmark.Items)
                {
                    item.IsExpanded = true;
                }



                //this.Cursor = Cursors.Arrow;
            }
            catch (Exception)
            {
                //MessageBox.Show("a");
                //throw;
            }
            //return tvBookmark;
        }

        /// <summary>
        /// Load notes which belong to a specific page
        /// </summary>
        /// <param name="pageNumber"></param>
        /// <returns></returns>
        public override List<Note> LoadNotesOfPage(int pageNumber)
        {
            return null;
        }

        /*        public override void DisposeControl()
                {
                    axAcroPDF1.Dispose();
                }*/



        //********************************************************************************
        [DllImport("user32.dll", SetLastError = true)]
        static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);

        public const int KEYEVENTF_EXTENDEDKEY = 0x0001; //Key down flag
        public const int KEYEVENTF_KEYUP = 0x0002; //Key up flag
        public const int VK_LCONTROL = 0xA2; //Left Control key code
        public const int A = 0x41; //A Control key code
        public const int C = 0x43; //C Control key code
        public const int F = 0x46; //A Control key code

        public override void PressKeys()
        {

            // Hold Control down and press C
            /*            keybd_event(VK_LCONTROL, 0, KEYEVENTF_EXTENDEDKEY, 0);
                        keybd_event(C, 0, KEYEVENTF_EXTENDEDKEY, 0);
                        keybd_event(C, 0, KEYEVENTF_KEYUP, 0);
                        keybd_event(VK_LCONTROL, 0, KEYEVENTF_KEYUP, 0);*/
            //this.axAcroPDF1.Focus();
            keybd_event(VK_LCONTROL, 0, 0, 0);
            keybd_event(C, 0, 0, 0);
            keybd_event(C, 0, 2, 0);
            keybd_event(VK_LCONTROL, 0, 2, 0);
            //MessageBox.Show("aaa");
        }

        /// <summary>
        /// Search for content
        /// </summary>
        /// <param name="content">desired texts</param>
        public override void SearchContent(string content)
        {
            this.axAcroPDF1.Focus();
            keybd_event(VK_LCONTROL, 0, 0, 0);
            keybd_event(F, 0, 0, 0);
            keybd_event(F, 0, 2, 0);
            keybd_event(VK_LCONTROL, 0, 2, 0);
        }

        public static void addTreeNode(XmlNode xmlNode, TreeViewItem treeNode)
        {
            XmlNode xNode;
            TreeViewItem tNode;
            XmlNodeList xNodeList;
            string strInnerText;
            string strPageNumber;
            string strXPath;
            if (xmlNode.HasChildNodes) //The current node has children
            {
                xNodeList = xmlNode.ChildNodes;
                if (xNodeList.Count > 1)
                {
                    if (xmlNode.Name.Equals("Bookmark"))
                    {
                        for (int x = 0; x <= xNodeList.Count - 1; x++)
                        //Loop through the child nodes
                        {
                            xNode = xmlNode.ChildNodes[x];
                            strInnerText = xNode.InnerText;
                            if (strInnerText.Contains("\n"))
                            {
                                strInnerText = xNode.InnerText.Substring(0, xNode.InnerText.IndexOf("\n"));
                            }

                            treeNode.Items.Add(new TreeViewItem() { Header = strInnerText.Trim() });

                            tNode = treeNode.Items[x] as TreeViewItem;
                            addTreeNode(xNode, tNode);


                        }
                    }
                    else
                    {
                        for (int x = 1; x <= xNodeList.Count - 1; x++)
                        //Loop through the child nodes
                        {
                            xNode = xmlNode.ChildNodes[x];
                            strInnerText = xNode.InnerText;
                            if (strInnerText.Contains("\n"))
                            {
                                strInnerText = xNode.InnerText.Substring(0, xNode.InnerText.IndexOf("\n"));
                            }

                            treeNode.Items.Add(new TreeViewItem() { Header = strInnerText.Trim() });

                            tNode = treeNode.Items[x - 1] as TreeViewItem;
                            addTreeNode(xNode, tNode);


                        }
                    }
                }
                else
                {
                    xNode = xmlNode.ChildNodes[0];
                    treeNode.Header = xNode.InnerText.Trim();

                }

            }
            else
            {
                //No children, so add the outer xml (trimming off whitespace)         
                treeNode.Header = xmlNode.OuterXml.Trim();

            }


        }

        public override string GetBookmarkPageNumber(RoutedPropertyChangedEventArgs<object> e, string strSelectedItem)
        {
            string strBookmarkPageNumber = "";
            string strNodePath = "/Bookmark/";
            Stack<TreeViewItem> path = GetNodeParent(e.NewValue as UIElement);
            foreach (var treeViewItem in path)
            {
                strNodePath += "Title" + "/";
            }
            if (strNodePath.Length > 1)
            {
                //strNodePath += strSelectedItem.Substring(0, strSelectedItem.Length -1);
            }

            strNodePath = strNodePath.Substring(0, strNodePath.Length - 1);

            //String.Format(strNodePath);

            strNodePath += "[contains(text(),'" + strSelectedItem.Trim() + "')]";
            //strNodePath.Replace("'", String.Format((char) 39));
            node = xDoc.SelectSingleNode(strNodePath);
            if (node != null)
            {
                XmlNode node2 = node.Attributes["Page"];
                if (node2 != null)
                {
                    string strPageNumber = node2.Value;
                    strPageNumber = strPageNumber.Substring(0, strPageNumber.IndexOf(" "));
                    if (strPageNumber != null)
                    {
                        strBookmarkPageNumber = strPageNumber;
                    }
                }

            }
            return strBookmarkPageNumber;
        }

        public static Stack<TreeViewItem> GetNodeParent(UIElement element)
        {

            Stack<TreeViewItem> tempNodePath = new Stack<TreeViewItem>();
            // Walk up the element tree to the nearest tree view item. 
            TreeViewItem container = element as TreeViewItem;


            while ((element != null))
            {

                element = VisualTreeHelper.GetParent(element) as UIElement;
                container = element as TreeViewItem;
                if (container != null)
                    tempNodePath.Push(container);
            }

            return tempNodePath;
        }


        public override Ebook GenerateEbookObj(string filePath)
        {
            Ebook myEbook = new Ebook();
            //File type
            FileInfo temp = new FileInfo(filePath);
            if (temp.Extension.Equals(".pdf", StringComparison.InvariantCultureIgnoreCase))
            {
                myEbook.Type = ".pdf";
            }
            PdfReader metaReader = new PdfReader(filePath);
            myEbook.PageCount = metaReader.NumberOfPages;
            myEbook.Title = Path.GetFileNameWithoutExtension(filePath);
            if (!metaReader.Info.ContainsKey("Author"))
            {
                myEbook.Author = "";
            }
            else
            {
                myEbook.Author = metaReader.Info["Author"].Trim();
                if (String.IsNullOrWhiteSpace(myEbook.Author))
                {
                    myEbook.Author = "N/A";
                }
            }
            myEbook.Path = filePath;
            myEbook.ImportDate = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
            myEbook.Rating = 0;
            myEbook.Publisher = "";
            myEbook.CurrentPage = 1;
            metaReader.Close();

            myEbook.Group = new List<string>();
            myEbook.BookmarkPath = "AeReaderData\\Temp\\" + myEbook.Title + ".xml";
            //TODO later
            if (!File.Exists(myEbook.BookmarkPath))
            {
                ExportBookmarksToXml(filePath, myEbook.BookmarkPath, "");
            }
            return myEbook;
        }

        public override void SetReadingMode(int mode) { }
        public override void SetFontSize(int size) { }
        public override void SetFontType(string type) { }
        public override void HightLightWord(string word) { }

        public override void GetPdfThumbnail(string sourcePdfFilePath, string destinationPngFilePath)
        {
            try
            {
                // Use GhostscriptSharp to convert the pdf to a png
                GhostscriptWrapper.GenerateOutput(sourcePdfFilePath, destinationPngFilePath,
                                                  new GhostscriptSettings
                                                      {
                                                          Device = GhostscriptDevices.png16m,
                                                          Page = new GhostscriptPages
                                                                     {
                                                                         // Only make a thumbnail of the first page
                                                                         Start = 1,
                                                                         End = 1,
                                                                         AllPages = false
                                                                     },
                                                          Resolution = new System.Drawing.Size
                                                                           {
                                                                               // Render at 72x72 dpi
                                                                               //Height = 72,
                                                                               //Width = 72
                                                                               Height = 30,
                                                                               Width = 30
                                                                           },
                                                          Size = new GhostscriptPageSize
                                                                     {
                                                                         // The dimentions of the incoming PDF must be
                                                                         // specified. The example PDF is US Letter sized.
                                                                         Native = GhostscriptPageSizes.letter
                                                                         //Native = GhostscriptPageSizes.c6 //323x459	
                                                                     }
                                                      }
                    );
            }
            catch(Exception ex){}
        }


    }
}